/*-------------------------------------------------------------------------

***************** Modification History ***********************************
   @doc
   @module Tip.c - Tip functionality |
   @end
   
$Log: /SoftPay/SPK2SIM/Source/Tran/tip.c $ 
**************************************************************************

   Copyright (C) 1999 by VeriFone, Inc.

   All rights reserved.  No part of this software may be reproduced,
   transmitted, transcribed, stored in a retrieval system, or translated
   into any language or computer language, in any form or by any means,
   electronic, mechanical, magnetic, optical, chemical, manual or otherwise,
   without the prior written permission of VeriFone, Inc.

---------------------------------------------------------------------------*/
#include <project.h>

#define VSTIP_C

#include <stdlib.h>
#include <applidl.h>
#include <aclconio.h>
#include <aclstr.h>
#include <actutil.h>
#include <string.h>

/** /#define DEBUG_VSTIP*/
#ifdef DEBUG_VSTIP
#define DEBUG_95
#endif

#include <define.h>
#include <transact.h>
#include <tip.h>
#include <gds.h>
#include <cst.h>
#include <cdt.h>
#include <hdt.h>
#include <tct.h>
#include <trt.h>
#include <ui.h>
#include <msg.h>
#include <msgfuncs.h>
#include <spdebug.h>
#include <tran.h>
#include <amount.h>
#include <pinpad.h>
#include <codesec.h>
#include <passwd.h>
#include <menus.h>
#include <oper.h>
#include <mdlfuncs.h>
#include <funcs.h>

/*-------------------------------------------------------------------------
    Function :    inComputePercent
    Description : Gets the tip % from the TCT, calculates the tip.
    Parameters :  (*inGetPercent) : function pointer to get percent.
                  szCalcAmt       : detination amount
                  inFractionalSize: number of digits after decimal
    Globals :     srGDS.BaseTransactionAmount
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      1   07/17/95 Eddy_B1    Removed code that computed the sum of the transaction
                              amount plus the tip amount and updated the transaction
                              amount w/ this new sum.
      2   08/20/95 Ana_C1     Routine changed to handle tax also.
      3   09/11/95 Hari_P1    Replaced ERR & NOERR with VS_ERR & VS_SUCCESS
      4   10/20/95 Ana_C1     Function pointer passed.
      5   08/30/96 Pat_G1     Divide by 100 instead of 10000.
      6   02/18/97 Kevin_v1   Modified to use 4 digit tax percentage.
      7   03/10/98 Kevin_v1   Modified to compute in 2 parts in order to handle large amounts.
      8   03/16/98 Kevin_v1   Modified to accept amount to compute percentage on as parameter.
 --------------------------------------------------------------------------*/
#if INVALID
int inComputePercent (long lnPercent, char *szCalcAmt, long lnBaseAmt, int inFractionalSize)
{
int     inAmtLen, inLoopCnt;
long    lnAmt, lnPct, lnSub1, lnSub2;
char    szLnAmt[12], szLnSub1[12], szLnSub2[12];
long    lnDivisor = 100;

    /**/pdebug (("---inComputePercent---"));/**/

    for(inLoopCnt = 0; inLoopCnt < inFractionalSize; inLoopCnt++)
        lnDivisor *= 10L;
    lnAmt = lnBaseAmt;
    lnPct = (long) lnPercent;
    memset (szLnAmt, 0, sizeof (szLnAmt));
    long2str (szLnAmt, lnAmt);
    /**/pdebug (("szLnAmt = %s", szLnAmt));/**/
    inAmtLen = strlen (szLnAmt);
    strcpy (szLnSub1, szLnAmt);
    strcpy (szLnSub2, szLnAmt);
    lnSub1 = 0L;
    /*
     *      If we have more than 4 digits, load upper digits into Sub1
     *      and lower digits into Sub2
     */
    if ( (inAmtLen = strlen (szLnAmt)) > 4 )
    {
        memset (szLnSub2, 0, sizeof (szLnSub2));
        memcpy (szLnSub2, &szLnAmt[inAmtLen-4], 4);
        /**/pdebug (("szLnSub2 = %s", szLnSub2));/**/
        szLnSub1[inAmtLen-1] = szLnSub1[inAmtLen-2] = szLnSub1[inAmtLen-3] = szLnSub1[inAmtLen-4] = '0';
        /**/pdebug (("szLnSub1 = %s", szLnSub1));/**/
        lnSub1 = str2long(szLnSub1);
    }
    lnSub2 = str2long (szLnSub2);
    /**/pdebug (("lnSub1 = %ld", lnSub1));/**/
    /**/pdebug (("lnSub2 = %ld", lnSub2));/**/    
//    lnSub1 = ( (lnSub1 / lnDivisor) * lnPct );
    lnSub1 = ( (lnSub1 * lnPct) / lnDivisor);
    lnSub2 = ( (lnSub2 * lnPct) / lnDivisor );
    lnAmt = lnSub1 + lnSub2;
    /**/pdebug (("lnSub1 = %ld", lnSub1));/**/
    /**/pdebug (("lnSub2 = %ld", lnSub2));/**/
    /**/pdebug (("lnAmt = %ld", lnAmt));/**/

    sprintf(szCalcAmt, SUBSTITUTE_LD, lnAmt);
    /**/pdebug(("Computed Amt = %s", szCalcAmt));/**/

    return(VS_SUCCESS);
}
#endif /* INVALID */
int inComputePercent (long lnPercent, char *szCalcAmt, long lnBaseAmt, int inFractionalSize)
{
    int inLoopCnt;
    double dbAmount;
    long lnDivisor = 100;
    long lnPercentValue = 0;

    /**/pdebug(("---inComputePercent---"));/**/

    for (inLoopCnt = 0; inLoopCnt < inFractionalSize; inLoopCnt++)
        lnDivisor *= 10L;
    dbAmount = (double) lnBaseAmt;
    lnPercentValue = (long) ((dbAmount / lnDivisor) * lnPercent);

    sprintf(szCalcAmt, SUBSTITUTE_LD, lnPercentValue);
    /**/pdebug(("Computed Amt = %s", szCalcAmt));/**/

    return(VS_SUCCESS);
}

/*-------------------------------------------------------------------------
    Function : inGetTip
    Description : it calls ingettiportax, then it saves the tip
                  to the GDS.
    Returns :     VS_ERR     : error in one of the inputs
                  VS_SUCCESS : value stored.
    Globals :     srGDS.szTipAmount
    Notes :
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      0   10/20/95 Ana_C1     Creation.
      1   06/19/96 Helen_d1   Changed flow to not prompt for % or $, defaults
                              is $ amount
      2   06/22/96 Jim_B4     Compute Tip if amount in TCT TipPercent
      3   07/03/96 Helen_D1   Added TipOn check from TCT table
      4   07/05/96 Page_K1    Move '}' that matches if(fGetTCTTipOn) so that
                              it is outside ifdef for DEBIT & PP101
      5   07/19/96 Helen_D1   Changed logic flow for TipOn.  Only check flag
                              if transaction type = SALE.  Allows user to turn
                              off tip without taking out of flow
      6   09/06/96 Donncha_H1 Flushed terminal keypresses which may occur during
                              PPad tip processing.
      7   09/19/96 Donncha_H1 Display the Tipe Entry message on the terminal.
      8   10/08/96 Page_K1    Save Old trans amt on adjust offline sale
      9   10/09/96 Pat_G1     Store total transaction amount before getting the
                              tip on the PIN pad.
     10   12/06/96 Donncha_H1 Removed #ifdef DEBIT and now checks the debit flag
     11   03/11/96 Page_K1    Always prompt for tip on DEBIT tran
     12   12/16/97 Betty_B1   Tip adjust was not setting the old tran amt
     13   12/16/97 Betty_B1   Change to use inGetTRTTransactionCode() 
                              instead of inGGCode() to test for
                              ADJUST_SALE_OFFLINE
     14   12/19/97 Page_K1    Remove FOLIO check  
     15   01/08/98 Page_K1    Use pobTran->fTipAdjust instead of trans code
     16   01/13/98 Page_K1    Set pobTran->srBRec.lnOldTipAmount
     17   01/14/98 Kevin_v1   Modified to use SPA_MESSAGE_FILE.
     18   03/11/98 Monique_B1 Move tip percent to the highest priority
     19   03/18/98 Page_K1    Check fGetTCTTipOn() instead of fGetTCTTipProc() if
                              Sale and not fGetTCTTipOn()  
     20   03/18/98 Page_K1    Check fGetTRTOverage() == VS_TRUE instead of 
                                inGGCode() == SALE (positive and negative) to
                                determine if we get the tip
--------------------------------------------------------------------------*/

int inGetTip(TRANSACTION_OBJECT* pobTran) {
    char szAmt[AMT_SIZE + 1],
    * szDisplaySymbol;
    int inRetVal = VS_SUCCESS;
    int inSurcharge;
    long lnTipAmt;
    char szDisplayBuffer[DISP_STR_LEN + 1];

    inSurcharge = 0;

    /** /pdebug(("--inGetTip--"));*/

    pobTran->srBRec.fTipEntered = VS_FALSE;

    /** /pdebug(("GGCode %d", inGGCode()));*/
    /** /pdebug(("TAmt %ld", pobTran->srBKey.lnTotalOfTransactionAmount));*/

    if (pobTran->fTipAdjust) {
        pobTran->srBRec.lnOldTotalTransactionAmount = pobTran->srBKey.lnTotalOfTransactionAmount;
        pobTran->srBRec.lnOldTipAmount = pobTran->srBRec.lnTipAmount;
    }

    if ((inGetTipPercent() > 0) && (inGetTipProcessing() > TIP_OFF)) {
        pobTran->srBRec.fTipEntered = VS_TRUE;
        inRetVal = inComputePercent((long) inGetTipPercent(), szAmt, pobTran->srBRec.lnBaseTransactionAmount, TIP_FORMAT);
        pobTran->srBRec.lnTipAmount = str2long(szAmt);
        return(inRetVal);
    }

    if ((inGetTipProcessing() == TIP_ON_PROMPT && !(fGetCounterPayTip() && inGGCode() == SALE)) || ((inGGCode() == SALE && inGetTipProcessing() > TIP_OFF) && (pobTran->srBRec.inTranCardType == DEBIT_CARD || pobTran->srBRec.inTranCardType == EBT_CARD)) || ((inGGCode() == REFUND_DEBIT && inGetTipProcessing() > TIP_OFF) && (pobTran->srBRec.inTranCardType == DEBIT_CARD || pobTran->srBRec.inTranCardType == EBT_CARD))) {
        /** /pdebug(("after tip proc chk.."));*/
        pobTran->srBRec.fTipEntered = VS_TRUE;

#if 0   /* No tip entry from PinPad anymore -- begin */ 
#ifdef PINPAD_DEFINED

            /* Old Check for getting tip on PINPad required 
               DEBIT, now we will just check the Get Tip PINPad flag */
               
            /* Display a prompt on terminal to indicate Tip entry required */
            if ((fGetPinTip() == VS_TRUE) && (inGetPINPadType() != NO_PINPAD))
            {  
                vdDisplayMessageFromFile( ENTER_TIP_MSG, STATUS_MSG);
                vdWarnBeep();
                
                if ( pobTran->srBRec.lnSChgAmount > 0L )
                {
                    inSurcharge = pobTran->srBRec.lnSChgAmount;
                }

                pobTran->srBKey.lnTotalOfTransactionAmount = 
                    pobTran->srBRec.lnBaseTransactionAmount + 
                    pobTran->srBRec.lnTaxAmount +
                    pobTran->srBRec.lnCashBackAmount +
                    (long) inSurcharge;
                                              
                inRetVal =  inGetPinTip(pobTran);
                switch(inRetVal)
                {
                    case PP_SUCCESS:    /* No error...continue       */
                        break;

                    case PP_TIMEOUT:    /* An Error Occurred...      */
                        vdSGErrorMessage(ERR_ENTERING_TIP_MSG);
                        return(VS_ERROR);

                    case PP_CANCEL:     /* An Error Occurred...      */
                        vdSGErrorMessage(TXN_CANCELLED);
                        return(VS_ERROR);

                    case PP_CORRECT:    /* Corr pressed: code to loop*/
                        vdBeep();
                        vdSGErrorMessage(CUSTOMER_REQ_CORR_ERR_MSG);
                        return(PP_CORRECT);

                    case PP_ERROR:      /* An Error Occurred...      */
                    default:        /* Unknown Error Occurred... */
                        vdSGErrorMessage(PINPAD_ERR_MSG21);
                        INCREMENT_PINPAD_ERROR;
                        return(VS_ERROR);
                }
                /* Clear PIN Message in status line */
                vdDisplayMessageFromFile( EMPTY_STR_ERR_MSG, STATUS_MSG);

                vdFlushKeyboardBuffer();    /* Any keypresses occurring on the terminal */
                                            /* during PPad processing are flushed */
            }    
            else
#endif  /* PINPAD_DEFINED */
#endif  /* No tip entry from PinPad anymore -- end */
         {
            do {
                vdDisplayMessageFromFile(TIP_AMT_MSG, ENTRY_MSG);
                memset(szAmt, 0, sizeof(szAmt));

                szDisplaySymbol = szGetCurSymbol();
                vdGetMessageFromFile(TIP_AMT_MSG, szDisplayBuffer);
                //          BT_TRACE ('I', szDisplayBuffer);
                if ((inRetVal = inGetAmount(szAmt, VS_TRUE, 0L, 999999999L, szDisplaySymbol)) != VS_SUCCESS)
                    return(inRetVal);

                lnTipAmt = atol(szAmt);

                if (fExcessiveTip(pobTran, lnTipAmt)) {
                    // Coding this instead of using ERROR_MSG because we
                    // need to be consistant with the key presses used in
                    // Batch Review - see review.c / inBatchReviewTipAdjust()
                    vdDisplayMessageFromFile(TOO_MUCH_TIP_MSG, STATUS_MSG);
                    vdBeep();
                    vdFlushKeyboardBuffer();
                    inRetVal = inWaitKey(inGetIdleTimeOut());

                    if (inRetVal != KEY_CANCEL) {
                        if (inGetPwdFromUser(ACCESS_WITH_MANAGER_PASSWORD, NO_PIT_INDEX) != VS_ESCAPE) {
                            pobTran->srBRec.lnTipAmount = lnTipAmt;
                            inRetVal = VS_SUCCESS;
                        } else {
                            inRetVal = VS_ESCAPE;
                            break;
                        }
                    } else {
                        // Try again 
                        clrscr();
                        continue;
                    }
                } else {
                    pobTran->srBRec.lnTipAmount = lnTipAmt;
                    inRetVal = VS_SUCCESS;
                }
            } while (inRetVal != VS_SUCCESS && !act_kbd_pending_test(KEY_CANCEL));   

            pobTran->srBRec.lnTipAmount = str2long(szAmt);
        } /* end else no tip on pinpad */
    } /* end if prompting for tip */

    return(inRetVal);
} /* End of inGetTip () */


/*-------------------------------------------------------------------------
   Function :    fExcessiveTip
    Description :   Determines if Tip entered is too much base on Excessive 
Tip Percentage in TCT table
    Parameters :
    Returns :   VS_TRUE, VS_FALSE
    Globals :
    Notes :
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      0   01/25/00 KC_C1      Created
--------------------------------------------------------------------------*/
VS_BOOL fExcessiveTip(TRANSACTION_OBJECT* pobTran,long lnTipAmt) {
    int inRetVal = VS_FALSE;
    char szCalcAmt[FORMATTED_AMOUNT_SIZE + 1];
    long lnCalcAmt;

    if (inGetExcessTip() > 0 && lnTipAmt > 0) {
        inComputePercent((long) inGetExcessTip(), szCalcAmt, pobTran->srBRec.lnBaseTransactionAmount, WHOLE_PERCENT_FORMAT);
        lnCalcAmt = str2long(szCalcAmt);
        if (lnTipAmt >= lnCalcAmt)
            inRetVal = VS_TRUE;
    }

    return (inRetVal);
}    



/*-------------------------------------------------------------------------
    Function :    inGetTax
    Description : it calls ingettiportax, then it saves the tax
                  to the GDS.
    Returns :     VS_ERR     : error in one of the inputs
                  VS_SUCCESS : value stored.
    Globals :     srGDS.szTaxAmount
    Notes :
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      0   10/20/95 Ana_C1     Creation.
      1   01/22/97 Kevin_V1   Modified to always prompt for TAX on 
                              PURCHASE_CARD transactions.
--------------------------------------------------------------------------*/
#ifndef  REMOVE_CORE_GET_TAX

int inGetTax(TRANSACTION_OBJECT* pobTran) {
    char szAmt[AMT_SIZE + 1],
    * szDisplaySymbol;
    int inRetVal;
    char szDisplayBuffer[DISP_STR_LEN + 1];
    long lnMaxAmt;


    /** /pdebug(("--inGetTax--"));*/

    /* prompt for tax on loyalty */
    if (fGetTaxProc() == VS_TRUE || pobTran->srBRec.inTranCardType == PURCHASE_CARD) {
        pobTran->srBRec.fTaxEntered = VS_TRUE;
        if (lnGetTaxPercent() > 0L) {
            inRetVal = inComputePercent(lnGetTaxPercent(), szAmt, pobTran->srBRec.lnBaseTransactionAmount, TAX_FORMAT);
            pobTran->srBRec.lnTaxAmount = str2long(szAmt);
            return(inRetVal);
        }


        vdDisplayMessageFromFile(TAX_AMOUNT_MSG21, ENTRY_MSG);
        memset(szAmt, 0, sizeof(szAmt));

        szDisplaySymbol = szGetCurSymbol();
        vdGetMessageFromFile(TAX_AMOUNT_MSG21, szDisplayBuffer);
        //       BT_TRACE ('I', szDisplayBuffer);

        // use base amount as max tax amount entry 
        // if it's purchase card transaction and not auto calculate tax
        if (pobTran->srBRec.inTranCardType == PURCHASE_CARD && fGetTaxProc() == VS_FALSE && lnGetTaxPercent() <= 0L)
            lnMaxAmt = pobTran->srBRec.lnBaseTransactionAmount;
        else
            lnMaxAmt = 999999999L;

        if ((inRetVal = inGetAmount(szAmt, VS_TRUE, 0L, lnMaxAmt, szDisplaySymbol)) != VS_SUCCESS)
            return(inRetVal);
        /** /pdebug(("szAmt = %s", szAmt));*/
        pobTran->srBRec.lnTaxAmount = str2long(szAmt);

        /* added for adjusting tax through batch review */
        if (fGetTaxProc() == VS_TRUE)
            pobTran->srBKey.lnTotalOfTransactionAmount = pobTran->srBRec.lnBaseTransactionAmount + pobTran->srBRec.lnTipAmount + pobTran->srBRec.lnTaxAmount + pobTran->srBRec.lnCashBackAmount;
    }
    return (VS_SUCCESS);
}


#endif /*  #ifndef  REMOVE_CORE_GET_TAX */


/*-------------------------------------------------------------------------
    Function :    fComputeOverage()
    Description : Determines whether or not the overage percentage should
                  be calculated.
    
    Returns :     VS_TRUE    : calculate the overage percentage
                  VS_FALSE   : do not calculate the overage percentage.
    Globals :     
    Notes :
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      0   08/21/97 Pat_G1     Creation.
      1   08/21/97 Pat_G1     Added lnGGTipAmount() == 0L condition.
      2   09/04/97 Pat_G1     Removed !fVFSwitchedTransaction() condition 
                              since it is specific to Visa.
      3   09/04/97 Pat_G1     If floor limit TRT bit is on and amount is less
                              than floor limit, do not compute overage.
      4   01/07/98 Kevin_V1   Pass pobTran to fAmountLessThanFloorLimit()
      5   03/18/98 Page_K1    Reverse logic to check false conditions
--------------------------------------------------------------------------*/
VS_BOOL fComputeOverage(TRANSACTION_OBJECT* pobTran) {
    if (/* Not at Debit/EBT Card - AND */
        (pobTran->srBRec.inTranCardType == DEBIT_CARD) || (pobTran->srBRec.inTranCardType == EBT_CARD) ||  
        /* TRT Overage flag is ON - AND */
        (fGetOverage(pobTran) == VS_FALSE) || ((fGetCheckFloorLimit(pobTran) == VS_TRUE) && (fAmountLessThanFloorLimit(pobTran) == VS_TRUE)) || 

        /* Tip Processing is OFF */    
        (inGetTipProcessing() == TIP_OFF) || 
        /* Tip Processing is ON - AND */    
        ((inGetTipProcessing() > TIP_OFF) && 
            /* Tip Entered or Tip */
             (pobTran->srBRec.fTipEntered == VS_TRUE)))
        return(VS_FALSE);
    else
        return(VS_TRUE);
}

/*-------------------------------------------------------------------------
    Function :    inGetCounterPayTip()
    Description : Process tip at the end of each transaction instead of doing 
    a mass tip adjust at the end of a shift/day.
    
    Returns :     VS_SUCCESS : Complete tip adjust and batch record updated
                  VS_ERR     : incomplete tip adjust
    Globals :     
    Notes :
    Modification History :
      #     Date      Who                     Description
    ----- -------- ---------- ---------------------------------------------
      0   10/21/99 ed_y1      
      1   09/11/00 Terri_L1    added line to set operation code to tip_adjust
                               operation.  The code will work fine as long as
                               counter pay tip is the last transaction flow
                               item.  If it is not, this function will have
                               to be modified so that the operation and
                               transaction codes are set back to their
                               original values.
--------------------------------------------------------------------------*/
#ifndef  REMOVE_CORE_COUNTER_PAY_TIP

int inGetCounterPayTip(TRANSACTION_OBJECT* pobTran) {
    int inRetVal = VS_SUCCESS;

    if ((fGetCounterPayTip()) && (inGetTipProcessing() == TIP_OFF))
        return(VS_SUCCESS);

    if (!fGetCounterPayTip() || ((inGetTipPercent() > 0) && (inGetTipProcessing() > TIP_OFF)) || ((inGGCode() == SALE) && (pobTran->srBRec.inTranCardType == DEBIT_CARD || pobTran->srBRec.inTranCardType == EBT_CARD)))
        return(VS_SUCCESS);

    pobTran->fTipAdjust = VS_TRUE;
    pobTran->fCounterPayTip = VS_TRUE;

    inInitPrintOption(pobTran);

    /* Set Operation Code to TIP_ADJUST_OPERATION; */
    /* Counter pay tip must be last tansaction flow item */
    vdSGOpCode(TIP_ADJUST_OPERATION);

    inLoadTRTRec(pobTran, TIP_ADJUST);

    vdClearStatusMessage();
    vdSGErrorMessage(0L); /* clear error message */
    if (!fGetAllowed(pobTran)) {
        vdDisplayMessageFromFile(TRANS_NOT_ALLWD_ERR_MSG, ERROR_MSG);
        return(VS_ERR);
    }

    if (inCheckBannedCardType(pobTran) == VS_ERR)
        return(VS_ERR);

    if ((inRetVal = inRunEngine(pobTran->srTRTRec.shFieldFuncPtr, pobTran)) != VS_SUCCESS) {
        /* vdVoidAdjustError(pobTran, inResult, VS_TRUE); */
        pobTran->fTipAdjust = VS_FALSE;
        return(VS_ERR);
    }

    return(inRetVal);
}

#endif /* #ifndef  REMOVE_CORE_COUNTER_PAY_TIP */



int TIP_CODE_CHECK(char* a,char* b,short* c,char* d,unsigned char* e) {
    GET_VER(a, b, c, d, e);
    return 1;
}

#undef VSTIP_C

